/**
 * JAVACC DEMO 1.0
 */
package com.apache.portal.filter;

import com.apache.api.vo.ResultMsg;
import com.apache.client.IBaseReplaceCard;
import com.apache.client.UctCoreClient;
import com.apache.passport.common.PassportHelper;
import com.apache.passport.common.XmlWhiteUtils;
import com.apache.portal.common.oscache.OsCacheManager;
import com.apache.portal.common.util.PortalPubFactory;
import com.apache.portal.common.util.PortalUtil;
import com.apache.tools.ConfigUtil;
import com.apache.tools.RequestTools;
import com.apache.tools.StrUtil;
import com.apache.uct.common.LoginUser;
import com.apache.uct.common.PBOSSOTools;
import com.apache.uct.common.ToolsUtil;
import com.apache.uct.common.entity.Role;
import org.apache.log4j.Logger;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * description:
 *
 * @author dyhou 创建时间：2017-7-28
 */
public class AopFilter extends PortalPubSuperFilter {

    private Logger logger = Logger.getLogger(getClass());

    /**
     * TODO 简单描述该方法的实现功能（可选）.
     *
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        //resp.setCharacterEncoding("UTF-8");
        resp.setDateHeader("expires", 0);
        resp.setHeader("Cache-Control", "no-cache");
        resp.setHeader("pragma", "no-cache");
        req.setCharacterEncoding("UTF-8");
        String path_ = req.getContextPath();
        String basePath_ =
                req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + path_
                        + "/";
        //设置退出路径  页面中直接${outUrl}即可
        req.getSession().setAttribute("outUrl", basePath_);

        String uri = req.getRequestURI();//获取uri信息
        String suffix = PassportHelper.getInstance().parseUrlSuffix(uri);//获取后缀名
        if (StrUtil.isNotNull(suffix)) {//如果存在后缀为图片,css等格式,直接跳过,不拦截
            suffix = suffix.toLowerCase();//后缀名小写
            if (SUFFIX.contains(suffix)) {
                chain.doFilter(req, resp);
                return;
            }
        }
        /**验证安全模块（sql注入，跨站脚本 攻击等**/
        super.initValue();
        boolean checkFlag = checkSecurity(req);
        if (checkFlag) {
            logger.error("拦截安全攻击：" + checkFlag);
            this.sendErrorPage(req, resp);
            return;
        }
        //获取token
        String tokenCookie = PassportHelper.getInstance().getCurrCookie(req);
        String seTokenId = String.valueOf(oscache.get(req.getSession().getId()));
        seTokenId = StrUtil.doNull(seTokenId, tokenCookie);
        //获取访问路径
        String path = req.getContextPath();

        //2015年2月4日11:07:24 更新 如果客户端根据token访问获取
        String pkt = req.getParameter("tokenId");
        if ("undefined".equalsIgnoreCase(pkt))
            pkt = "";
        //2015年6月8日15:55:16  获取请求中携带的参数
        boolean isMobile = PortalPubFactory.getInstance().JudgeIsMoblie(req);
        String tokenId = seTokenId;
        if (isMobile) {
            tokenId = StrUtil.doNull(pkt, tokenId);
        }
        boolean tokenMark = false;
        String mobileType = request.getParameter("userAgent");
        if ("wx".equals(mobileType)) {
            tokenMark = true;
        } else {
            if (ConfigUtil.getInstance().checkFileUpdate("")) {
                initValue();
            }
            if (StrUtil.isNotNull(tokenId) && (!uri.equals(path + "/logout") && !uri
                    .equals(path + "/cset"))) {
                tokenMark = auditTokenAndSso(tokenId, tokenCookie, req, resp);
            }
        }
        LoginUser loginUser = PortalUtil.getInstance().getLoginUser(req);
        if (isMobile) {//手机移动端
            if (tokenMark) {
                if (ToolsUtil.isEmpty(loginUser)) {
                    if ("wx".equals(mobileType)) {
                        loginUser = PortalUtil.getInstance().getUserForWx(tokenId);
                    } else {
                        loginUser = PBOSSOTools.getLoginUserFromUserCenterSso(tokenId);
                    }
                }
                if (!ToolsUtil.isEmpty(loginUser)) {
                    OsCacheManager.getInstance().putLoginUser(tokenId, loginUser);
                }
                chain.doFilter(req, resp);
                return;
            } else {
                if (StrUtil.isNull(tokenCookie) && StrUtil.isNull(pkt)) {
                    clearCookie(req, resp, "/");
                    if (StrUtil.isNotNull(tokenId)) {
                        ResultMsg msg = new ResultMsg("F", "登录tokenId已失效");
                        net.sf.json.JSONObject json = net.sf.json.JSONObject.fromObject(msg);
                        if (StrUtil.isNotNull(json.toString())) {
                            response.setContentType("text/html;charset=UTF-8");
                            PrintWriter out = response.getWriter();
                            out.print(json);
                            out.flush();
                            out.close();
                        }
                        return;
                    }
                }
            }
        } else if (StrUtil.isNull(tokenId) && StrUtil.isNotNull(pkt)) {//客户端根据token访问获取
            String clientUrl = doSsoFilter(req, resp, tokenId, pkt);
            resp.sendRedirect(clientUrl);
            return;
        } else {//pC正常访问
            if (tokenMark) {
                loginUser = doUctFilter(req, resp, tokenId);
                if (req.getRequestURI().equals(path + "/logout") || req.getRequestURI()
                        .equals(path + "/cset")) {
                } else {
                    if (!ToolsUtil.isEmpty(loginUser)) {
                        if ("T".equals(
                                ToolsUtil.getInstance().getValueByKey("local_user"))) {//用户换证处理操作
                            String reflectPath = ToolsUtil.getInstance()
                                    .getValueByKey("reflect_path");
                            try {
                                if (StrUtil.isNotNull(reflectPath)) {
                                    Class<?> clazz = Class.forName(reflectPath);
                                    IBaseReplaceCard replaceCard = (IBaseReplaceCard) clazz
                                            .newInstance();
                                    if (!replaceCard
                                            .replaceCard(loginUser, req, resp)) {//数据插入到本地，并且换证
                                        resp.sendRedirect(req.getContextPath() + "/");
                                        return;
                                    }
                                }
                            } catch (Exception e) {
                                logger.error(e);
                            }
                        }
                        //只需登录的url地址处理
                        String NORIGHT_URL = UctCoreClient.getConf_Map().get("noright_url");
                        if (ToolsUtil.isNotNull(NORIGHT_URL)) {
                            String str = NORIGHT_URL;
                            String[] wus = str.split(",");
                            for (int i = 0; i < wus.length; i++) {
                                String wurl = wus[i];
                                if (ToolsUtil.isNotNull(wurl)) {
                                    if (path.startsWith(wurl)) {
                                        chain.doFilter(req, resp);
                                        return;
                                    }
                                }
                            }
                        }
                        chain.doFilter(req, resp);
                        return;
                    }
                }
            }
        }
        String loginUrl = doSsoFilter(req, resp, tokenId, "");
        //CookeHeader(req, resp);
        //退出操作
        if (req.getRequestURI().equals(path + "/logout")) {
            doLogout(req, resp, chain, tokenId, loginUrl);
        } else if (req.getRequestURI().equals(path + "/cset")) {
            setCookie(req, resp);//设置cookie
        } else {
            if (tokenMark) {
                chain.doFilter(req, resp);
                return;
            } else {
                if (!StrUtil.isNull(tokenId) || null != loginUser) {
                    clearCookie(req, resp, "/");
                }
                boolean mark = whitePathFiter(uri, req);//白名单处理
                if (mark) {
                    chain.doFilter(req, resp);
                    return;
                } else {
                    //resp.sendRedirect(req.getContextPath() + StrUtil.doNull(customLogin, "/login.jsp"));
                    resp.sendRedirect(req.getContextPath() + StrUtil.doNull(customLogin, "/"));
                }
            }
        }
    }

    private LoginUser doUctFilter(HttpServletRequest request, HttpServletResponse response,
            String tokenId) {
        LoginUser loginUser = (LoginUser) request.getSession().getAttribute(sessionKey);
        if (ToolsUtil.isNull(tokenId)) {
            clearCookie(request, response, "/");
        } else {
            //通过token及用户名去uc获取用户对象
            if (null == loginUser) {
                loginUser = OsCacheManager.getInstance().getLoginUser(tokenId);//从缓存中获取
                if (null == loginUser) {
                    String value = PassportHelper.getInstance().getCurrCookie(request, "_uc.sso");
                    if (ToolsUtil.isNull(value)) {
                        return null;
                    }
                    //value = DesUtils.getInstance().decrypt(value);//解密
                    loginUser = UctCoreClient.getLoginUserFromUserCenterSso("", tokenId);
                }
                if (!ToolsUtil.isEmpty(loginUser)) {
                    request.getSession().setAttribute("cookieToken", tokenId);
                }
            }
        }
        if (!ToolsUtil.isEmpty(loginUser)) {
            request.getSession().setAttribute(sessionKey, loginUser);//获取session中信息
            if (ToolsUtil.isEmpty(request.getSession().getAttribute("loginUserRoles"))) {
                List<Role> roles = PBOSSOTools.getRolesForLoginUser(request);//获取用户角色列表
                if (!ToolsUtil.isEmpty(roles)) {
                    request.getSession().setAttribute("loginUserRoles", roles);
                }
            }
        }
        return loginUser;
    }

    /**
     * description: sso参数组装
     */
    private String doSsoFilter(HttpServletRequest request, HttpServletResponse response,
            String tokenId, String pkt) throws UnsupportedEncodingException {
        String path = request.getServletPath();
        //要跳转到哪个url
        String gotoURL = request.getParameter("go");
        String csetUrl = request.getScheme() + "://" + request.getServerName() + ":" + request
                .getServerPort() + path;
        if (gotoURL == null) {
            gotoURL = request.getRequestURL().toString();
        }
        //Map<String, String> map = new HashMap<String, String>(1);
        String reqParams = "";//customLogin
        if ("T".equals(ToolsUtil.getInstance().getValueByKey("is_url_params"))) {
            reqParams = PassportHelper.getInstance().getReqParams(request, "go");
            reqParams = PassportHelper.getInstance().isNov(reqParams, reqParams, "?" + reqParams);
        }

        ArrayList<String> lst = new ArrayList<String>();

        if (StrUtil.isNull(tokenId) && StrUtil.isNotNull(pkt)) {//客户端调用
            StringBuffer tokenUrl = new StringBuffer();
            lst.add(login_url);
            lst.add(pkt);
            lst.add(gotoURL + reqParams);
            lst.add("apache");
            lst.add(csetUrl);
            Collections.sort(lst);
            String sha1Rtn = PassportHelper.getInstance().SHA1(lst);
            logger.info("login_url=" + login_url + "====pkt=" + pkt);
            if ("T".equals(login_pass)) {
                //如果cookie为空,则跳转到登录页面
                tokenUrl.append(login_url);
                tokenUrl.append("?");
                tokenUrl.append("ptlang=" + sha1Rtn);
                tokenUrl.append("&");
                tokenUrl.append("tokenId=" + pkt);//设置远程cookie
                tokenUrl.append("&");
                tokenUrl.append("go=" + gotoURL + reqParams);
                tokenUrl.append("&");
                tokenUrl.append("cset=" + csetUrl);
            } else {
                tokenUrl.append(login_url);
            }
            request.removeAttribute("tokenId");
            //map.put("client_url", tokenUrl.toString());
            return tokenUrl.toString();
        }/////客户端调用结束

        //统一登录系统平台回调参数
        String cset = csetUrl + "/cset";
        lst.add(login_url);
        lst.add(sysEname);
        lst.add(cset);
        if (request.getRequestURI().equals(path + "/logout")) {
            lst.add(gotoURL);
        } else {
            lst.add(gotoURL + reqParams);
        }
        lst.add("apache");
        Collections.sort(lst);
        String sha1Rtn = PassportHelper.getInstance().SHA1(lst);
        StringBuffer loginUrl = new StringBuffer();
        if ("T".equals(login_pass)) {
            //如果cookie为空,则跳转到登录页面
            loginUrl.append(login_url);
            loginUrl.append("?");
            loginUrl.append("_client=" + sha1Rtn);
            loginUrl.append("&");
            loginUrl.append("sys=" + sysEname);//系统名称
            loginUrl.append("&");
            loginUrl.append("cset=" + URLEncoder.encode(cset, "UTF-8"));//设置远程cookie
            loginUrl.append("&");
            loginUrl.append("go=" + URLEncoder.encode(gotoURL, "UTF-8") + reqParams);
        } else {
            loginUrl.append(login_url);
        }
        //map.put("login_url", loginUrl.toString());
        return loginUrl.toString();
    }

    /**
     * description: 验证tokenId是否有效
     */
    private boolean auditTokenAndSso(String tokenId, String cookieId, HttpServletRequest req,
            HttpServletResponse resp) {
        //		String value = PassportHelper.getInstance().getCurrCookie(req, "_uc.sso");
        if (StrUtil.isNotNull(tokenId)) {
            String ss[] = tokenId.split("\\|");
            tokenId = ss[0];
            String jsonStr = "";
            String cacheKey = "checkToken_" + tokenId;
            String cacheObj = String.valueOf(oscache.get(cacheKey));
            if (StrUtil.isNotNull(cacheObj) && StrUtil.isNotNull(cookieId))
                return true;
            try {
                net.sf.json.JSONObject result = this
                        .ssoSend(tokenId, RequestTools.getIp(req), "checkToken", "");
                if (result.getBoolean("result")) {
                    String entity = result.getString("entity");
                    String message = result.getString("message");
                    if (tokenId.equalsIgnoreCase(entity)) {
                        Cookie ticket = new Cookie(cookieName, tokenId);
                        ticket.setPath("/");
                        ticket.setMaxAge(-1);
                        Cookie ucssoCKey = new Cookie("_uc.sso", message);
                        ucssoCKey.setPath("/");
                        ucssoCKey.setMaxAge(-1);
                        resp.addCookie(ticket);
                        resp.addCookie(ucssoCKey);
                        oscache.put(cacheKey, entity);
                        return true;
                    }
                }
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        }
        return false;
    }

    /**
     * description: 白名单验证
     */
    private boolean whitePathFiter(String uri, HttpServletRequest req) {
        //初始化白名单
        String path = req.getServletPath();
        if (path.indexOf("sendPage.action") != -1 || path.indexOf("/admin/") != -1)
            return false;
        XmlWhiteUtils.getInstance().deWhiteXml(whiteMap, sysCode);
        String whiteUrl = "/error.action,/errorPage,";
        /**白名单处理*/
        if (StrUtil.isNotNull(whiteUrl)) {
            String[] wus = whiteUrl.split(",");
            for (int i = 0; i < wus.length; i++) {
                String wurl = wus[i];
                if (StrUtil.isNotNull(wurl)) {
                    if (path.startsWith(wurl)) {
                        return true;
                    }
                }
            }
        }
        ArrayList<String> whiteUrl2 = whiteMap.get("whiteUrl");
        ArrayList<String> whiteParadigm = whiteMap.get("whiteParadigm");
        String ctx = req.getContextPath(); //获取上下文，如/项目名
        uri = uri.substring(ctx.length());
        //url白名单
        if (whiteUrl2.contains(uri)) {
            return true;
        } else {
            int wp = whiteParadigm.size();
            if (uri.length() > 1) {//主要是/造成,如guo/后面有内容,则进入以下方法
                for (int i = 0; i < wp; i++) {
                    if ((whiteParadigm.get(i)).contains("*")) {
                        String wdir = (whiteParadigm.get(i)).replace("*", "");
                        int s = uri.indexOf(wdir);
                        if (s == 0) {
                            return true;
                        }
                    } else {
                        if (!"".equals(whiteParadigm.get(i))) {
                            int s = uri.indexOf(whiteParadigm.get(i));
                            if (s == 0) {
                                return true;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * description:  用户退出操作
     */
    private void doLogout(HttpServletRequest req, HttpServletResponse resp, FilterChain chain,
            String tokenCookie, String loginUrl) {
        try {
            //clearCookie(req, resp, "/");
            String gotoURL = StrUtil
                    .doNull(req.getParameter("go"), StrUtil.doNull(customLogin, "/index.jsp"));
            if (StrUtil.isNull(tokenCookie)) {
                clearCookie(req, resp, "/");
                resp.sendRedirect(req.getContextPath() + gotoURL);
                return;
            }
            long startlong = System.currentTimeMillis();
            String userEname = PassportHelper.getInstance().getCurrCookie(req, "_uc.sso");
            if (StrUtil.isNull(userEname)) {
                userEname = (String) req.getSession().getAttribute("message");
            }
            //2015年2月3日09:31:48 update 退出时根据配置文件内容,自动判断操作协议,进行操作,原只支持socket
            net.sf.json.JSONObject result = this
                    .ssoSend(tokenCookie, RequestTools.getIp(req), "logout", userEname);
            if (result.getBoolean("result")) {
                clearCookie(req, resp, "/");
                logger.warn("logout : userEname=" + userEname + ";" + (System.currentTimeMillis()
                        - startlong));
            } else {
                logger.info("passport msg : 与统一登录系统通讯失败,操作[证书认证]失败");
            }
            resp.sendRedirect(req.getContextPath() + gotoURL);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * description:  设置本地cookie
     */
    private void setCookie(HttpServletRequest req, HttpServletResponse resp) {
        String token = req.getParameter("ticket");
        String ucsso = req.getParameter("ucsso");
        String gotoURL = req.getParameter("go");
        Cookie ticket = new Cookie(cookieName, token);
        ticket.setPath("/");
        ticket.setMaxAge(-1);

        Cookie ucssoCKey = new Cookie("_uc.sso", ucsso);
        ucssoCKey.setPath("/");
        ucssoCKey.setMaxAge(-1);

        try {
            resp.addCookie(ticket);
            resp.addCookie(ucssoCKey);
            if (StrUtil.isNotNull(gotoURL)) {
                gotoURL = gotoURL.replaceAll("\\|", "&");
                if (gotoURL.indexOf("?tokenId=") != -1) {
                    gotoURL = gotoURL.replaceAll("tokenId=" + token + "&", "");
                } else {
                    gotoURL = gotoURL.replaceAll("&tokenId=" + token, "");
                }
                resp.sendRedirect(gotoURL);
            }
        } catch (IOException e) {
            logger.warn(e.getMessage());
        }

    }
}
